package com.charon.common.interceptor;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ApplicationObjectSupport;
import org.springframework.core.NamedThreadLocal;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.charon.common.util.DateUtils;
import com.charon.common.util.StringUtils;
import com.charon.module.operator.dao.NetworkRecordEntityMapper;
import com.charon.module.operator.entity.NetworkRecordEntity;

import net.sf.json.JSONObject;

/**
 * @Description: 日志拦截器
 * @author charon [248135724@qq.com]
 * @date: 2018年9月3日 上午9:29:03
 */
public class LogInterceptor extends ApplicationObjectSupport implements HandlerInterceptor {
	protected Logger logger = LoggerFactory.getLogger(getClass());
	private static final ThreadLocal<Long> startTimeThreadLocal = new NamedThreadLocal<Long>("ThreadLocal StartTime");
	private static final HashMap<String, Integer> sessionMap = new HashMap<String, Integer>();
	private static NetworkRecordEntityMapper nrem = null;

	/**
	 * 该方法会在请求进入时调用
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		long beginTime = System.currentTimeMillis();// 1、开始时间
		startTimeThreadLocal.set(beginTime); // 线程绑定变量（该数据只有当前请求的线程可见）
		logger.info("开始计时: {}  URI: {}", new SimpleDateFormat("HH:mm:ss.SSS").format(beginTime),
				request.getRequestURI());
		//获取ApplicationContext对象
		ApplicationContext applicationContext = getApplicationContext();
		insertRecord(request,applicationContext);
		return true;
	}

	/**
	 * 该方法会在返回服务端时调用
	 */
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		if (modelAndView != null) {
			logger.info("ViewName: " + modelAndView.getViewName());
		}
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		if (startTimeThreadLocal != null && startTimeThreadLocal.get() != null) {
			// 打印JVM信息。
			long beginTime = startTimeThreadLocal.get();// 得到线程绑定的局部变量（开始时间）
			long endTime = System.currentTimeMillis(); // 2、结束时间
			logger.info("计时结束：{}  耗时：{}  URI: {}  最大内存: {}m  已分配内存: {}m  已分配内存中的剩余空间: {}m  最大可用内存: {}m",
					new SimpleDateFormat("HH:mm:ss.SSS").format(endTime), DateUtils.formatDateTime(endTime - beginTime),
					request.getRequestURI(), Runtime.getRuntime().maxMemory() / 1024 / 1024,
					Runtime.getRuntime().totalMemory() / 1024 / 1024, Runtime.getRuntime().freeMemory() / 1024 / 1024,
					(Runtime.getRuntime().maxMemory() - Runtime.getRuntime().totalMemory()
							+ Runtime.getRuntime().freeMemory()) / 1024 / 1024);
			// 删除线程变量中的数据，防止内存泄漏
			startTimeThreadLocal.remove();
		}
	}

	/**
	 * 插入请求记录
	 * 
	 * @param request
	 */
	public static void insertRecord(HttpServletRequest request,ApplicationContext ac) {
		HttpSession session = request.getSession();
		if (session != null) {
			if (!sessionMap.containsKey(session.getId())) {
				JSONObject json = new JSONObject();
				Map<String, String[]> pramMap = request.getParameterMap();
				json.put("postValue", pramMap);
				StringBuffer url = request.getRequestURL();
				String param = request.getQueryString();
				String ip = getIpAdrress(request);
				String method = request.getMethod();
				// 如果是空，先初始化Dao
				if (nrem == null)
					getDaoImplement(ac);
				NetworkRecordEntity record = new NetworkRecordEntity();
				if (url.toString().contains("mercury")) {
					record.setCreateBy(2 + "");
					record.setCreateDate(new Date());
					record.setDelFlag(0 + "");
					record.setIp(ip);
					record.setMethod(method);
					record.setGetParam(param);
					if (json.toString().length() > 3000) {
						record.setPostParam(json.toString().substring(3000));
					} else {
						record.setPostParam(json.toString());
					}
					record.setOperator("mercury");
					record.setUrl(url.toString());
					record.setUpdateBy("mercury");
					record.setUpdateDate(new Date());
				} else if(url.toString().toUpperCase().contains("CHARON")) {
					if (session.getAttribute("userName") != null) {
						record.setCreateBy(session.getAttribute("id").toString());
						record.setOperator(session.getAttribute("userName").toString());
					}
					record.setCreateDate(new Date());
					record.setDelFlag(0 + "");
					record.setIp(ip);
					record.setMethod(method);
					record.setGetParam(param);
					record.setUrl(url.toString());
					if (json.toString().length() > 3000) {
						record.setPostParam(json.toString().substring(3000));
					} else {
						record.setPostParam(json.toString());
					}
					if(session.getAttribute("id")!=null){
						record.setUpdateBy(session.getAttribute("id").toString());
					}
					record.setUpdateDate(new Date());
				}
				int id = nrem.insertSelective(record);
				sessionMap.put(session.getId(), id);
			}
		}
	}

	/**
	 * 通过Mybatis获取Dao接口实现类用的
	 * 
	 * @return
	 */
	public static NetworkRecordEntityMapper getDaoImplement(ApplicationContext ac) {

		//SqlSessionFactory sqlSessionFactory = null;
		//Reader reader;
		/*try {
			reader = Resources.getResourceAsReader("config/Configure.xml");
			sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
			sqlSessionFactory.getConfiguration().addMapper(NetworkRecordEntityMapper.class);
		} catch (Exception e) {
			e.printStackTrace();
		}
		if (sqlSessionFactory == null) {
			throw new SqlSessionException("sqlSessionFactory获取失败");
		}
		*/
		nrem=ac.getBean(NetworkRecordEntityMapper.class);
		if(nrem==null){
			throw new BeanCreationException("Bean获取失败");
		}
		return nrem;
	}

	/**
	 * 获取客户端真实IP
	 * 
	 * @param request
	 * @return
	 */
	private static String getIpAdrress(HttpServletRequest request) {
		String Xip = request.getHeader("X-Real-IP");
		String XFor = request.getHeader("X-Forwarded-For");
		String ip=request.getRemoteAddr();
		if (StringUtils.isEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)) {
			// 多次反向代理后会有多个ip值，第一个ip才是真实ip
			int index = XFor.indexOf(",");
			if (index != -1) {
				return XFor.substring(0, index);
			} else {
				return XFor;
			}
		}
		XFor = Xip;
		if (StringUtils.isEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)) {
			return XFor;
		}
		if (!StringUtils.isEmpty(XFor) || "unknown".equalsIgnoreCase(XFor)) {
			XFor = request.getHeader("Proxy-Client-IP");
		}
		if (!StringUtils.isEmpty(XFor) || "unknown".equalsIgnoreCase(XFor)) {
			XFor = request.getHeader("WL-Proxy-Client-IP");
		}
		if (!StringUtils.isEmpty(XFor) || "unknown".equalsIgnoreCase(XFor)) {
			XFor = request.getHeader("HTTP_CLIENT_IP");
		}
		if (!StringUtils.isEmpty(XFor) || "unknown".equalsIgnoreCase(XFor)) {
			XFor = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		if (!StringUtils.isEmpty(XFor) || "unknown".equalsIgnoreCase(XFor)) {
			XFor = request.getRemoteAddr();
		}
		return XFor+"|"+ip;
	}
}
